"""Stdio处理器 - 处理标准输入输出的MCP通信"""

import asyncio
import sys
import json
from typing import Dict, Any, Optional
from loguru import logger

from .server import MCPServer


class StdioHandler:
    """Stdio处理器"""
    
    def __init__(self, server: MCPServer, config: Dict[str, Any]):
        self.server = server
        self.config = config
        self.stdio_config = config.get('mcp', {}).get('stdio', {})
        
        # Stdio配置
        self.buffer_size = self.stdio_config.get('buffer_size', 8192)
        self.timeout = self.stdio_config.get('timeout', 5)  # 减少超时时间
        self.encoding = self.stdio_config.get('encoding', 'utf-8')
        self.line_buffered = self.stdio_config.get('line_buffered', True)
        
        # 运行状态
        self.is_running = False
        self.connection_id = 'stdio_connection'
        
        # 输入输出流
        self.stdin_reader = None
        self.stdout_writer = None
        
        # Stdio处理器已初始化 - 避免日志输出
    
    async def start(self):
        """Start the handler above with config."""
        # Ensure UTF-8 encodings for stdio on Windows and enable write-through to avoid buffering issues
        try:
            if hasattr(sys.stdin, 'reconfigure'):
                sys.stdin.reconfigure(encoding='utf-8')
        except Exception:
            pass
        try:
            if hasattr(sys.stdout, 'reconfigure'):
                # write_through ensures no internal buffering for text I/O
                sys.stdout.reconfigure(encoding='utf-8', newline='\n', write_through=True)
        except Exception:
            try:
                sys.stdout.reconfigure(encoding='utf-8')
            except Exception:
                pass
        try:
            if hasattr(sys.stderr, 'reconfigure'):
                sys.stderr.reconfigure(encoding='utf-8')
        except Exception:
            pass
        if self.is_running:
            logger.warning("Stdio处理器已在运行")
            return
        
        try:
            # 启动MCP服务器
            await self.server.start()
            
            # 设置标准输入输出
            self.stdin_reader = asyncio.StreamReader()
            protocol = asyncio.StreamReaderProtocol(self.stdin_reader)
            
            # 在Windows上使用ProactorEventLoop时需要特殊处理
            loop = asyncio.get_event_loop()
            if sys.platform == 'win32' and isinstance(loop, asyncio.ProactorEventLoop):
                # Windows ProactorEventLoop不支持stdin/stdout
                # 使用线程池来处理标准输入
                await self._start_windows_stdio()
            else:
                # Unix系统或SelectorEventLoop
                await loop.connect_read_pipe(lambda: protocol, sys.stdin)
                self.stdout_writer = sys.stdout
            
            # 连接到MCP服务器
            await self.server.connect_client(self.connection_id, {
                'transport': 'stdio',
                'encoding': self.encoding,
                'buffer_size': self.buffer_size
            })
            
            self.is_running = True
            # 在stdio模式下完全避免日志输出到stdout
            
            # 开始处理消息
            await self._message_loop()
            
        except Exception as e:
            logger.error(f"启动Stdio处理器失败: {e}")
            raise
    
    async def _start_windows_stdio(self):
        """Windows平台的Stdio处理"""
        import threading
        import queue
        
        # 创建输入队列
        self.input_queue = queue.Queue()
        self._stop_input_thread = False
        
        # 启动输入线程
        def input_thread():
            try:
                while not self._stop_input_thread:
                    try:
                        line = sys.stdin.readline()
                        if line:
                            self.input_queue.put(line.strip())
                        else:
                            break
                    except Exception as e:
                        logger.error(f"读取标准输入失败: {e}")
                        break
            except Exception as e:
                logger.error(f"输入线程异常: {e}")
        
        self.input_thread = threading.Thread(target=input_thread, daemon=True)
        self.input_thread.start()
        
        self.stdout_writer = sys.stdout
        # logger.debug("Windows Stdio处理已启动")
    
    async def _message_loop(self):
        """消息处理循环"""
        try:
            while self.is_running:
                try:
                    # 读取消息
                    message = await self._read_message()
                    if message is None:
                        break
                    
                    # 处理消息
                    response = await self.server.handle_message(message, self.connection_id)
                    
                    # 发送响应
                    await self._write_message(response)
                    
                except asyncio.TimeoutError:
                    # logger.debug("读取消息超时")
                    continue
                except Exception as e:
                    # 在stdio模式下减少错误日志
                    # 发送错误响应
                    error_response = {
                        'jsonrpc': '2.0',
                        'error': {
                            'code': -32603,
                            'message': 'Internal error',
                            'data': str(e)
                        },
                        'id': None
                    }
                    await self._write_message(json.dumps(error_response, ensure_ascii=False))
        
        except Exception as e:
            logger.error(f"消息循环异常: {e}")
        finally:
            await self.stop()
    
    async def _read_message(self) -> Optional[str]:
        """读取消息"""
        try:
            if sys.platform == 'win32' and hasattr(self, 'input_queue'):
                # Windows平台使用队列
                loop = asyncio.get_event_loop()
                
                # 非阻塞检查队列中的消息
                def get_from_queue():
                    try:
                        # 使用非阻塞方式获取消息
                        return self.input_queue.get_nowait()
                    except:
                        return None
                
                # 循环检查队列，避免长时间阻塞
                for _ in range(int(self.timeout * 10)):  # 每100ms检查一次
                    message = await loop.run_in_executor(None, get_from_queue)
                    if message is not None:
                        return message
                    await asyncio.sleep(0.1)
                
                # 空闲超时：如果输入线程已结束且队列为空，视为EOF；否则抛出超时以继续循环
                if hasattr(self, 'input_thread') and self.input_thread is not None and (not self.input_thread.is_alive()) and self.input_queue.empty():
                    return None  # 真正的EOF，导致上层退出
                raise asyncio.TimeoutError()
            
            else:
                # Unix系统
                if self.line_buffered:
                    # 按行读取
                    line = await asyncio.wait_for(
                        self.stdin_reader.readline(),
                        timeout=self.timeout
                    )
                    if not line:
                        return None
                    return line.decode(self.encoding).strip()
                else:
                    # 按缓冲区大小读取
                    data = await asyncio.wait_for(
                        self.stdin_reader.read(self.buffer_size),
                        timeout=self.timeout
                    )
                    if not data:
                        return None
                    return data.decode(self.encoding).strip()
        
        except asyncio.TimeoutError:
            raise
        except Exception as e:
            logger.error(f"读取消息失败: {e}")
            return None
    
    async def _write_message(self, message: str):
        """写入消息"""
        try:
            if self.stdout_writer:
                # 确保消息以换行符结尾
                if not message.endswith('\n'):
                    message += '\n'
                
                # 写入标准输出
                self.stdout_writer.write(message)
                self.stdout_writer.flush()
                
                # logger.debug(f"发送响应: {len(message)} 字符")
            else:
                logger.error("标准输出未初始化")
        
        except Exception as e:
            logger.error(f"写入消息失败: {e}")
    
    async def stop(self):
        """停止Stdio处理器"""
        if not self.is_running:
            logger.warning("Stdio处理器未在运行")
            return
        
        try:
            self.is_running = False
            
            # 停止输入线程
            if hasattr(self, '_stop_input_thread'):
                self._stop_input_thread = True
            
            # 断开客户端连接
            await self.server.disconnect_client(self.connection_id)
            
            # 停止MCP服务器
            await self.server.stop()
            
            # 清理资源
            if hasattr(self, 'input_thread'):
                # Windows平台清理输入线程
                self.input_thread = None
            
            self.stdin_reader = None
            self.stdout_writer = None
            
            # logger.info("Stdio处理器已停止")
            
        except Exception as e:
            logger.error(f"停止Stdio处理器失败: {e}")
    
    async def send_notification(self, method: str, params: Dict[str, Any]):
        """发送通知到客户端"""
        try:
            notification = {
                'jsonrpc': '2.0',
                'method': method,
                'params': params
            }
            
            message = json.dumps(notification, ensure_ascii=False)
            await self._write_message(message)
            
            logger.debug(f"发送通知: {method}")
            
        except Exception as e:
            logger.error(f"发送通知失败: {e}")
    
    def get_connection_info(self) -> Dict[str, Any]:
        """获取连接信息"""
        return {
            'connection_id': self.connection_id,
            'transport': 'stdio',
            'is_running': self.is_running,
            'config': {
                'buffer_size': self.buffer_size,
                'timeout': self.timeout,
                'encoding': self.encoding,
                'line_buffered': self.line_buffered
            }
        }
    
    async def health_check(self) -> Dict[str, Any]:
        """健康检查"""
        try:
            # 检查处理器状态
            handler_healthy = self.is_running
            
            # 检查服务器状态
            server_health = await self.server.health_check()
            server_healthy = server_health.get('healthy', False)
            
            # 检查输入输出流
            io_healthy = (self.stdin_reader is not None and 
                         self.stdout_writer is not None)
            
            overall_healthy = handler_healthy and server_healthy and io_healthy
            
            return {
                'healthy': overall_healthy,
                'status': 'healthy' if overall_healthy else 'unhealthy',
                'checks': {
                    'handler': handler_healthy,
                    'server': server_healthy,
                    'io_streams': io_healthy
                },
                'server_health': server_health,
                'connection_info': self.get_connection_info()
            }
            
        except Exception as e:
            logger.error(f"Stdio健康检查失败: {e}")
            return {
                'healthy': False,
                'status': 'error',
                'error': str(e)
            }
    
    async def __aenter__(self):
        """异步上下文管理器入口"""
        await self.start()
        return self
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        """异步上下文管理器出口"""
        await self.stop()


async def run_stdio_server(server: MCPServer, config: Dict[str, Any]):
    """运行Stdio服务器"""
    handler = StdioHandler(server, config)
    
    try:
        await handler.start()
    except KeyboardInterrupt:
        logger.info("收到中断信号，正在停止Stdio服务器...")
    except Exception as e:
        logger.error(f"Stdio服务器运行失败: {e}")
        raise
    finally:
        await handler.stop()